
namespace Nadine
{
	//====================================================================================
	class NDCHCSPNode :public NDBaseObject
	{
	private:
		//----- KD TREE -----
		sCHCSPNode*								m_myRootNode;				//the same as mHierarchyRoot
		CGrowableArray< sCHCSPNode* > 			m_myNodePool;

		int 	 								m_nGeometryThreshold;
		float 	 								m_fSurfaceThreshold;		// the maximum bounding box surface
		int 	 								m_nMaxDepth;				// the maximum tree depth
		float 	 								m_fBoxColor;				// the default bounding box drawing color

		//bool 									m_bRenderBoundingVolume;
		float 	 								m_fSplitBandwith;

		UINT									m_nNumHierarchyNodes;

		NDVECTOR4								m_vFrustumEq[6];
		int										m_nNPVertexIndices[12];

		NDVECTOR3								m_vViewPoint;
		NDMATRIX								m_mProjViewMatrix;

	protected:
		void			AddGeometryIntoNode( sCHCSPNode* pNode, NDCHCSPGeometry* pGeometry );
		sCHCSPNode*		newNode( const NDVECTOR3 boundLower, const NDVECTOR3 boundUpper, sCHCSPNode *parent, int depth);

		bool 			SimpleEnough(sCHCSPNode* pNode);								//! criteria to stop the splitting of this kd-tree node
		float 			ComputeSplitPlane( sCHCSPNode* pNode);							//! split plane of the kd-tree (according to mSplitAxis, it is the x, y, or z axis)

		/** calculates a value that expresses if it's reasonable to split the 
		   node at the specified position (the smaller the value the better the split)
		   */
		float 			ComputeHeuristics( sCHCSPNode* pNode, float pos);

		int				GenerateKdTree(sCHCSPNode* pNode);								//! generates the kd-tree from this root-node, returns number of nodes in hierarchy.

		//----- math operation -----
		float 	calcAABoxSurface( sNDCHCSPBBox aab );									// calculates surface of this aab
		void 	appendToCubicHull(NDVECTOR3* min, NDVECTOR3* max, const NDVECTOR3 v);
		void 	combineAABoxes(sNDCHCSPBBox* a, const sNDCHCSPBBox b);					// combines two AABs, stores result in a
		void 	clipAABoxByAABox(sNDCHCSPBBox *aab, const sNDCHCSPBBox enclosed);		// clips box aab by box enclosed
		void 	calcAABoxPoints(NDVECTOR3* points, const sNDCHCSPBBox b);				// calculates the 8 corner points of the given AABox
		void	calcAABNPVertexIndices(int* pNPVertexIndices, NDVECTOR4* pFrustumEq);
		int 	calcAABNearestVertexIdx(NDVECTOR3 clipPlaneNormal);
		int		calcAABFarthestVertexIdx(NDVECTOR3 clipPlaneNormal);
		void	calcAABoxCenter(NDVECTOR3* vec, const sNDCHCSPBBox aab);
		float   pointPlaneDistance(const NDVECTOR4 planeEq, const NDVECTOR3 p);
		bool 	pointBeforePlane(const NDVECTOR4 planeEq, const NDVECTOR3 p);



	public:
		explicit NDCHCSPNode(NDArk* pArk);
		virtual ~NDCHCSPNode()
		{
			assert( m_myNodePool.GetSize() ==0 );
		}

		virtual void release();

		//----- KD TREE -----
		void	AddGeometryIntoRootNode( NDCHCSPGeometry* pGeometry ) { this->AddGeometryIntoNode( this->m_myRootNode, pGeometry ); }


		/**
			initialises the k-d tree and the static termination criteria.
			this method must be called after all geometry has been added to the root node
			and before the tree has been generated.
		*/
		void 	InitKdTree();


		//! add children of this node ordered to a traversal stack with respect to the view point
		//void 	PushChildrenOrdered( sCHCSPNode* pNode, const NDVECTOR3 viewpoint, NDCHCSPTraversalStack &traversalStack);	

		bool 	IsLeaf(sCHCSPNode* pNode);												//! is this node a leaf node (i.e., geometry)

		int 	renderNode(sCHCSPNode* pNode, float fElapsedTime);						//! renders the geometry in this node. returns number of rendered geometry
		void 	renderBoundingVolume(sCHCSPNode* pNode);								//! renders the bounding volume  (i.e., a axis aligned bounding box) of the node		
		void 	renderBoundingVolumeForVisualization(sCHCSPNode* pNode);				//! set gl state to visible render bounding volume

		int 	getNumHierarchyNodes();									//! returns number of nodes in hierarchy with this node.
		sCHCSPNode* getRootNode() { return m_myRootNode; }

		void 	setViewpoint(NDVECTOR3 const &viewpoint);				//! sets viewpoint
		void	setFrustumEq(NDVECTOR4* pFrustumEq); 					//! NDVECTOR4[6]
		void	calcFrustumAABNPVertexIndices()	{ calcAABNPVertexIndices(m_nNPVertexIndices, m_vFrustumEq); }


		//! true if bounding box is culled by view frustum culling
		/**
			intersectsNearplane returns true if bounding box intersects the near plane.
			additionally stores the distance from the near plane to the center of the 
			current node with the node. this will for front-to-back ordering
		*/
		bool 	InsideViewFrustum(sCHCSPNode *node, bool &intersects);

		

	};

}